﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;

namespace FileArchiveConsole
{
    class Program
    {

        const int mb_size = 1024 * 1024;
        const int kb_size = 1024;
        const string file_reg_name = "filecommand.reg";
        const string file_dir_name = "dircommand.reg";

        static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                InfoProcess(args);
            }
            else
            {
                Console.WriteLine("Import Reg File");
                Process.Start(file_reg_name);
                Process.Start(file_dir_name);
                //Console.WriteLine("Do Not Have Args");
            }
            System.Console.Read();
        }

        private static void InfoProcess(string[] args)
        {

            Console.WriteLine("-----------------------  File  -----------------------------");
            Console.WriteLine("------------------------------------------------------------");

            PrintBaseInfomation(args[0]);
            PrintOptionInfomation(args[0]);

            Console.WriteLine("------------------------------------------------------------");
            Console.WriteLine("------------------------------------------------------------");
        }

        private static void PrintBaseInfomation(string path)
        {

            Console.WriteLine(string.Format("Current Dir: {0}", Environment.CurrentDirectory));
            Console.WriteLine(string.Format("Current FilePath: {0}", path));

            if (Directory.Exists(path))
            {
                long dir_size = 0;
                GetDirSizeByPath(path, ref dir_size);
                DirectoryInfo dirctoryInfo = new DirectoryInfo(path);
                Console.WriteLine(string.Format("Last WriteTime: {0}", dirctoryInfo.LastWriteTime));
                Console.WriteLine(GetSizeString(dir_size));
            }
            else
            {
                FileInfo fileinfo = new FileInfo(path);
                Console.WriteLine(string.Format("Current File MD5: {0}", Utils.GetMD5HashFromFile(path)));
                Console.WriteLine(string.Format("Current File SHA1: {0}", Utils.GetSHA1(path)));
                Console.WriteLine(string.Format("Is ReadOnly: {0}", fileinfo.IsReadOnly));
                Console.WriteLine(string.Format("Last WriteTime: {0}", fileinfo.LastWriteTime));
                Console.WriteLine(GetSizeString(fileinfo.Length));

                string endfix = Path.GetExtension(path);
                if (endfix == ".exe" || endfix == ".dll")
                {
                    FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(path);
                    string versionstr = fvi.FileMajorPart.ToString() + "_" + fvi.FileMinorPart.ToString() + "_" + fvi.FileBuildPart.ToString();
                    Console.WriteLine(string.Format("FileVersion: {0}", versionstr));

                    ushort arc = GetPEArchitecture(path);
                    if (arc == 0x10b)
                    {
                        Console.WriteLine(string.Format("Architecture: {0}", "32位"));
                    }
                    else if(arc == 0x20b)
                    {
                        Console.WriteLine(string.Format("Architecture: {0}", "64位"));
                    }

                }
            }
            

        }

        private static void PrintOptionInfomation(string path)
        {
            if (Directory.Exists(path))
            {
                //打印子文件列表
            }
        }

        private static string GetSizeString(long size)
        {
            if (size < kb_size)
            {
                return string.Format("FileSize: {0} Bytes", size);
            }
            else if (size < mb_size)
            {
                return string.Format("FileSize: {0} KB", size / (float)kb_size);
            }
            else if(size < mb_size * 1024)
            {
                return string.Format("FileSize: {0} MB", size / (float)mb_size);
            }
            else
            {
                return string.Format("FileSize: {0} GB", size / (float)(mb_size * 1024));
            }
        }

        /// <summary>
        /// 获取某一文件夹的大小
        /// </summary>
        /// <param name="dir">文件夹目录</param>
        /// <param name="dirSize">文件夹大小</param>
        public static void GetDirSizeByPath(string dir, ref long dirSize)
        {
            try
            {
                DirectoryInfo dirInfo = new DirectoryInfo(dir);

                DirectoryInfo[] dirs = dirInfo.GetDirectories();
                FileInfo[] files = dirInfo.GetFiles();

                foreach (var item in dirs)
                {
                    GetDirSizeByPath(item.FullName, ref dirSize);
                }

                foreach (var item in files)
                {
                    dirSize += item.Length;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("获取文件大小失败" + ex.Message);
            }

        }

        /// <summary>
        /// 判断程序或dll是x86还是x64(可能返回的两种结果：0x10b - PE32 0x20b - PE32+)
        /// </summary>
        /// <param name="pFilePath"></param>
        /// <returns></returns>
        public static ushort GetPEArchitecture(string pFilePath)
        {
            ushort architecture = 0;
            try
            {
                using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                    {
                        if (bReader.ReadUInt16() == 23117) //check the MZ signature
                        {
                            fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew.
                            fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header.
                            if (bReader.ReadUInt32() == 17744) //check the PE\0\0 signature.
                            {
                                fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header,
                                architecture = bReader.ReadUInt16(); //read the magic number of the optional header.
                            }
                        }
                    }
                }
            }
            catch (Exception) { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure */}
            //if architecture returns 0, there has been an error.
            return architecture;
        }

    }
}
